﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Configuration;
using Microsoft.WindowsAzure;

namespace CloudTrace.Reader
{
    public class QueueReader : CloudTraceReader
    {
        private CloudQueue queue;
        private int maxMessages;

        public string GetPlainTextMessage()
        {
            return this.GetPlainTextMessage(true);
        }

        public string GetPlainTextMessage(bool delete)
        {
            CloudQueueMessage message = GetMessageFromQueue(delete);
            if (null != message)
            {
                if (this.usePlaintext)
                {
                    return message.InsertionTime.ToString() + ": " + message.AsString;
                }
                else
                {
                    LogMessage logMessage = LogMessage.Deserialize(message.AsBytes);
                    return logMessage.Timestamp.ToString() + ": " + logMessage.Message;
                }
            }
            return null;
        }

        public string[] GetPlainTextMessages()
        {
            return this.GetPlainTextMessages(true);
        }

        public string[] GetPlainTextMessages(bool delete)
        {
            List<string> stringMessages = new List<string>();
            CloudQueueMessage[] messages = this.GetMessagesFromQueue(this.maxMessages, delete);

            foreach (CloudQueueMessage message in messages)
            {
                if (this.usePlaintext)
                {
                    stringMessages.Insert(0, message.InsertionTime.ToString() + ": " + message.AsString);
                }
                else
                {
                    LogMessage logMessage = LogMessage.Deserialize(message.AsBytes);
                    stringMessages.Insert(0, logMessage.Timestamp.ToString() + ": " + logMessage.Message);
                }
            }
            return stringMessages.ToArray();
        }

        public LogMessage GetLogMessage()
        {
            return this.GetLogMessage(true);
        }

        public LogMessage GetLogMessage(bool delete)
        {
            CloudQueueMessage message = GetMessageFromQueue(delete);
            if (null != message)
            {
                return this.usePlaintext ?
                    new LogMessage(message.AsString, string.Empty) : LogMessage.Deserialize(message.AsBytes);
            }
            return null;
        }

        public LogMessage[] GetLogMessages()
        {
            return this.GetLogMessages(true);
        }

        public LogMessage[] GetLogMessages(bool delete)
        {
            List<LogMessage> logMessages = new List<LogMessage>();
            CloudQueueMessage[] messages = this.GetMessagesFromQueue(this.maxMessages, delete);

            foreach (CloudQueueMessage message in messages)
            {
                logMessages.Insert(0, this.usePlaintext ?
                    new LogMessage(message.AsString, string.Empty) : LogMessage.Deserialize(message.AsBytes));
            }
            return logMessages.ToArray();
        }

        private CloudQueueMessage GetMessageFromQueue(bool delete)
        {
            if (null == this.queue)
                this.InitializeService();

            CloudQueueMessage message = null;
            try
            {
                message = queue.GetMessage();
                if (null != message && delete)
                    queue.DeleteMessage(message);
            }
            catch (StorageException storageClientException)
            {
                switch (storageClientException.RequestInformation.ExtendedErrorInformation.ErrorCode)
                {
                    case "MessageNotFound":
                        //deleted from a parallel app?
                        break;
                    case "PopReceiptMismatch":
                        break;
                    case "QueueDisabled":
                        break;
                    case "QueueNotFound":
                        break;
                    default:
                        throw;
                }
            }
            return message;
        }

        private CloudQueueMessage[] GetMessagesFromQueue(int maxMessages, bool delete)
        {
            if (null == this.queue)
                this.InitializeService();

            CloudQueueMessage[] messages = null;
            try
            {
                messages = queue.GetMessages(maxMessages).ToArray<CloudQueueMessage>();
                if (delete && null != messages)
                {
                    foreach (CloudQueueMessage message in messages)
                    {
                        queue.DeleteMessage(message);
                    }
                }
            }
            catch (StorageException storageClientException)
            {
                switch (storageClientException.RequestInformation.ExtendedErrorInformation.ErrorCode)
                {
                    case "MessageNotFound":
                        //deleted from a parallel app?
                        break;
                    case "PopReceiptMismatch":
                        break;
                    case "QueueDisabled":
                        break;
                    case "QueueNotFound":
                        break;
                    default:
                        throw;
                }
            }
            return messages;
        }

        public int MaxBatchSize
        {
            get { return this.maxMessages; }
            set { this.maxMessages = value; }
        }

        public int MessageCount
        {
            get
            {
                if (null != this.queue)
                {
                    queue.FetchAttributes();
                    if (queue.ApproximateMessageCount.HasValue)
                        return queue.ApproximateMessageCount.Value;
                }
                return -1;
            }
        }

        #region private helpers
        protected override void InitializeService()
        {
            base.Initialize();
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();

            this.queue = queueClient.GetQueueReference(CloudConfigurationManager.GetSetting(SupportedAttributes.queueName.ToString() ?? "QueueTraceListener").ToLowerInvariant());
            queue.CreateIfNotExists();
            this.usePlaintext = bool.Parse(CloudConfigurationManager.GetSetting(SupportedAttributes.usePlainText.ToString()) ?? bool.FalseString);
            this.maxMessages = CloudQueueMessage.MaxNumberOfMessagesToPeek;

        }
        #endregion
    }
}
